use anyhow::Context;
use axum::{
  Router, debug_handler,
  extract::{Query, State},
  routing::get,
};
use axum_valid::Valid;
use sea_orm::{Condition, QueryOrder, QueryTrait, prelude::*};
use serde::Deserialize;
use validator::Validate;

use crate::{
  app::AppState,
  common::{Page, PaginationParams},
  entity::{company, prelude::*},
  error::ApiResult,
  response::ApiResponse,
  yquery, yvalid,
};

#[derive(Debug, Deserialize, Validate)]
#[serde(rename_all = "camelCase")]
pub struct UserQueryParams {
  keyword: Option<String>,
  #[validate(nested)] // nested会深入到结构体中去校验
  #[serde(flatten)]
  pagination: PaginationParams,
}

pub type ApiResultResponse<T> = ApiResult<ApiResponse<T>>;

pub fn create_router() -> Router<AppState> {
  Router::new().route("/", get(find_page))
}

#[debug_handler]
async fn find_page(
  State(AppState { db }): State<AppState>,
  // 不使用axum的Query,和Valid,使用自定义的了
  yvalid::ValidQuery(UserQueryParams {
    keyword,
    pagination,
  }): yvalid::ValidQuery<UserQueryParams>,
) -> ApiResultResponse<Page<company::Model>> {
  let paginator = Company::find()
    .apply_if(keyword.as_ref(), |query, keyword| {
      query.filter(
        Condition::any()
          .add(company::Column::Name.contains(keyword))
          .add(company::Column::Address.contains(keyword)),
      )
    })
    .order_by_desc(company::Column::Age)
    .paginate(&db, pagination.size);
  let total = paginator.num_items().await?;
  let items = paginator.fetch_page(pagination.page - 1).await?;

  let page = Page::from_pagination(pagination, total, items);
  Ok(ApiResponse::ok("ok", Some(page)))
}

#[allow(unused)]
#[debug_handler]
async fn find_page_1(
  State(AppState { db }): State<AppState>,
  // 不使用axum的Query,和Valid,使用自定义的了
  yvalid::Valid(yquery::Query(UserQueryParams {
    keyword,
    pagination,
  })): yvalid::Valid<yquery::Query<UserQueryParams>>,
) -> ApiResultResponse<Page<company::Model>> {
  let paginator = Company::find()
    .apply_if(keyword.as_ref(), |query, keyword| {
      query.filter(
        Condition::any()
          .add(company::Column::Name.contains(keyword))
          .add(company::Column::Address.contains(keyword)),
      )
    })
    .order_by_desc(company::Column::Age)
    .paginate(&db, pagination.size);
  let total = paginator.num_items().await?;
  let items = paginator.fetch_page(pagination.page - 1).await?;

  let page = Page::from_pagination(pagination, total, items);
  Ok(ApiResponse::ok("ok", Some(page)))
}

#[allow(unused)]
#[debug_handler]
async fn query_users_1(
  State(AppState { db }): State<AppState>,
) -> ApiResultResponse<Vec<company::Model>> {
  let users = Company::find()
    .all(&db)
    .await
    .context("Failed to query users")?;
  Ok(ApiResponse::ok("ok", Some(users)))
}
